<template>
    <div>
        <div>
            <el-breadcrumb separator="/" style="margin: 8px;">
                <el-breadcrumb-item>预警结果数据</el-breadcrumb-item>
                <el-breadcrumb-item>供应链预警</el-breadcrumb-item>
                <el-breadcrumb-item>供应链预警结果详情</el-breadcrumb-item>
            </el-breadcrumb>
        </div>
        <div class="container">
            <h3 style="cursor: pointer;" @click="goback">
                <i class="el-icon-back"></i>
                供应链预警结果详情
            </h3>
            <el-row style="margin-top: 20px;">
                <el-col :span="3" :offset="1">
                    <h4>版本号</h4>
                    <p class="text">{{ resultData.version }}</p>
                </el-col>
                <el-col :span="3">
                    <h4>组件</h4>
                    <p class="text">{{ resultData.component }}</p>
                </el-col>
                <el-col :span="3">
                    <h4>生态</h4>
                    <p class="text">{{ resultData.ecology }}</p>
                </el-col>
                <el-col :span="3">
                    <h4>创建时间</h4>
                    <p class="text">{{ resultData.createTime }}</p>
                </el-col>
                <el-col :span="2" :offset="9" v-if="resultData != null && resultData.healthyPoint != null">
                    <el-button v-if="resultData.healthyPoint.score <= 6" type="success" plain size="mini">{{
                        resultData.healthyPoint.score }} 低危</el-button>
                    <el-button v-else-if="resultData.healthyPoint.score <= 8" type="warning" plain size="mini">{{
                        resultData.healthyPoint.score }} 中危</el-button>
                    <el-button v-else-if="resultData.healthyPoint.score <= 10" type="danger" plain size="mini">{{
                        resultData.healthyPoint.score }} 高危</el-button>
                    <el-button v-else type="info" plain size="mini">未知</el-button>
                </el-col>
            </el-row>
            <el-row style="margin-top: 30px;">
                <el-col :span="3" :offset="1">
                    <h4>预警结果展示</h4>
                </el-col>
            </el-row>
            <div class="echart" id="mychart" ref="chartWrapper"></div>
            <el-row style="margin-top: 20px;">
                <el-col :span="22" :offset="1">
                    <h4>tips {{ currentSelect.title }}</h4>
                    <p class="text">{{ currentSelect.desc }}</p>
                </el-col>
            </el-row>
        </div>

        <div class="container" style="margin-top:10px;">
            <h3>供应链预警</h3>
            <el-tabs v-model="activeName" type="card" style="margin-top: 20px;">
                <el-tab-pane label="搜索" name="搜索" />
                <el-tab-pane label="查看" name="查看" />
            </el-tabs>

            <div class="main-content">
                <!-- 搜索 -->
                <div class="left" v-if="activeName == '搜索'">
                    <el-form :model="search" label-width="70px">
                        <el-form-item label="版本号:">
                            <el-input placeholder="请输入版本号" v-model="search.version" resize="none"></el-input>
                        </el-form-item>
                        <el-form-item label="组件:">
                            <el-input placeholder="请输入组件" v-model="search.component" resize="none"></el-input>
                        </el-form-item>
                        <el-form-item label="生态:">
                            <el-input placeholder="请输入生态" v-model="search.ecology" resize="none"></el-input>
                        </el-form-item>
                    </el-form>
                    <el-button style="width: 100%;margin-top: 10px;" type="primary" @click="getGraphData">查询</el-button>
                </div>

                <!-- 查看table -->
                <div class="left" v-if="activeName == '查看'">
                    <div style="display: flex;align-items: center;margin-bottom: 10px;">
                        <div style="width: 70px;font-size: 14px;flex-shrink: 0;">图谱名称:</div>
                        <el-input size="mini" style="margin-right: 10px;"></el-input>
                        <el-button type="primary" size="mini" @click="getGraphList()">查询</el-button>
                        <el-button size="mini">重置</el-button>
                    </div>
                    <el-table :data="tableData" border>
                        <el-table-column prop="graphName" label="graphName"></el-table-column>
                        <el-table-column prop="spaceName" label="spaceName"></el-table-column>
                        <el-table-column label="操作" width="100" fixed="right">
                            <template slot-scope="scope">
                                <el-button type="text" @click="handleLook(scope.row)"
                                    style="margin-right: 10px;">查看</el-button>
                                <el-popconfirm title="确定要删除吗？" @confirm="handleDelete(scope.row)">
                                    <template #reference>
                                        <el-button type="text">删除</el-button>
                                    </template>
                                </el-popconfirm>
                            </template>
                        </el-table-column>
                    </el-table>
                </div>

                <!-- 图表 -->
                <div class="right" ref="mountNode" v-loading="loading" element-loading-text="加载中..."
                    element-loading-background="rgba(0, 0, 0, 0.3)">
                    <graph :data="graphData" @getChildren="getChildren" ref="graphDom" type="AI_supply"
                        @getGraphList="getGraphList" />
                </div>
            </div>
        </div>
    </div>
</template>

<script>
import * as echarts from "echarts";
import graph from '@/components/graph/graph.vue'

export default {
    components: {
        graph
    },
    data() {
        return {
            id: "",
            resultData: {},
            radarData: [],
            currentSelect: {
                title: "",
                desc: ""
            },
            loading: false,
            graphData: {},
            activeName: "搜索",
            tableData: [],
            search: {}
        };
    },
    mounted() {
        this.id = this.$route.query.id;
        this.getData();
        this.getGraphList()
    },
    methods: {
        getData() {
            //查询详情
            this.$http.fetchGet('api/warnMessage/listOne/' + this.id).then(res => {
                console.log("res", res);
                res.healthyPoint = JSON.parse(res.healthyPoint.replace(/^["']|["']$/g, '').replace('/', ''));
                res.securityRisk = JSON.parse(res.securityRisk.replace(/^["']|["']$/g, '').replace('/', ''));
                res.versionMaintenance = JSON.parse(res.versionMaintenance.replace(/^["']|["']$/g, '').replace('/', ''));
                res.impactScope = JSON.parse(res.impactScope.replace(/^["']|["']$/g, '').replace('/', ''));
                res.communityEngagement = JSON.parse(res.communityEngagement.replace(/^["']|["']$/g, '').replace('/', ''));
                this.resultData = res;
                this.controlResult(res);
                this.search = {
                    version: res.version,
                    component: res.component,
                    ecology: res.ecology
                }
                this.getGraphData();
            }).catch(err => {
                let res = {
                    "id": 3,
                    "healthyPoint": "{\"level\": \"低危\", \"score\": 3.81}",
                    "securityRisk": "{\"index\": [\"most_cvss\", \"direct_vul_num\", \"undirect_vul_num\", \"top5_cvss\"], \"score\": 0, \"description\": [[\"直接感染漏洞的最高cvss评分为 0.0 ，无风险；\", \"top5直接感染漏洞的cvss平均分为 0.0 ，无风险；\", \"top5直接感染漏洞的平均依赖度数为 0.0 ，离漏洞较近；\"]]}",
                    "impactScope": "{\"index\": [\"dependent_num\", \"github_fork\", \"github_star\"], \"score\": 7.32, \"description\": [[\"组件下游依赖数有 0 个，该组件热度较低；\", \"组件无Github项目链接，无star数量、fork数量\"]]}",
                    "versionMaintenance": "{\"index\": [\"version_days\", \"newest_days\", \"version_type\", \"closed_issues\", \"issue_time_days\"], \"score\": 6.96, \"description\": [[\"组件的该版本更新时间距今 0 天，小于半年，为新版本；\", \"组件的最新版本更新时间距今 0 天，该组件半年内有更新；\", \"组件无Github项目链接，无近一个月closed_issues数量，上次issue距今天数；\"]]}",
                    "communityEngagement": "{\"index\": [\"contributor\", \"readme_md\", \"contributing_md\"], \"score\": 6.5, \"description\": [[\"组件无GitHub项目链接、贡献者数量、readme_md文件、contributing_md文件等数据；\"]]}",
                    "createTime": "2024-06-26 11:22:11",
                    "component": "tensorflow",
                    "ecology": "pypi",
                    "version": "2.13.0rc2"
                }
                res.healthyPoint = JSON.parse(res.healthyPoint.replace(/^["']|["']$/g, '').replace('/', ''));
                res.securityRisk = JSON.parse(res.securityRisk.replace(/^["']|["']$/g, '').replace('/', ''));
                res.versionMaintenance = JSON.parse(res.versionMaintenance.replace(/^["']|["']$/g, '').replace('/', ''));
                res.impactScope = JSON.parse(res.impactScope.replace(/^["']|["']$/g, '').replace('/', ''));
                res.communityEngagement = JSON.parse(res.communityEngagement.replace(/^["']|["']$/g, '').replace('/', ''));
                this.resultData = res;
                this.controlResult(res);
            });
        },
        controlResult(res) {
            //安全风险  securityRisk
            //社区热度  communityEngagement
            //版本维护  versionMaintenance
            //影响范围  impactScope
            this.radarData = [res.securityRisk.score, res.communityEngagement.score, res.versionMaintenance.score, res.impactScope.score];
            this.initEcharts();
        },
        goback() {
            this.$router.back();
        },
        initEcharts() {
            const option = {
                title: {
                    text: ''
                },
                tooltip: {
                    show: false,
                    formatter: function () {
                        return '';
                    }
                },
                legend: {
                    show: false
                },
                radar:
                {
                    indicator: [
                        { text: '安全风险', max: 10, desc: this.resultData.securityRisk.description[0].toString().replace(/,/g, '') },
                        { text: '社区热度', max: 10, desc: this.resultData.communityEngagement.description[0].toString().replace(/,/g, '') },
                        { text: '版本维护', max: 10, desc: this.resultData.versionMaintenance.description[0].toString().replace(/,/g, '') },
                        { text: '影响范围', max: 10, desc: this.resultData.impactScope.description[0].toString().replace(/,/g, '') }
                    ],
                    splitArea: {
                        areaStyle: {
                            color: ['rgba(200, 200, 200, 0.2)', 'rgba(255, 255, 255, 0.2)',
                                'rgba(200, 200, 200, 0.2)', 'rgba(255, 255, 255, 0.1)'],
                            shadowColor: 'rgba(0, 0, 0, 0.5)',
                            shadowBlur: 1
                        }
                    },
                    splitLine: {
                        lineStyle: {
                            color: 'rgba(255, 255, 255, 0.5)',
                            type: 'dashed'
                        }
                    },
                    shape: 'circle', // 设置为多边形
                    radius: '70%', // 雷达图半径，可以是绝对值（像素）或相对值，百分比是相对于宽高中的最小值
                    center: ['50%', '50%'], // 雷达图中心位置，同样支持绝对值和相对值
                    startAngle: 90, // 雷达图的起始角度，默认为90度
                }
                ,
                series: [
                    {
                        Symbol: 'circle',
                        type: 'radar',
                        tooltip: {
                            trigger: 'item'
                        },
                        itemStyle: {
                            borderWidth: 50,
                            borderColor: 'transparent'
                        },
                        areaStyle: {},
                        data: [
                            {
                                value: this.radarData,
                                name: '数据'
                            }
                        ]
                    }
                ]


            };
            const myChart = echarts.init(document.getElementById("mychart"));// 图标初始化
            myChart.setOption(option);// 渲染页面
            //随着屏幕大小调节图表
            window.addEventListener("resize", () => {
                myChart.resize();
            });
            myChart.on('mousemove', (params) => {
                let num = params.event.topTarget.__dimIdx;
                if (num === undefined) {
                    option.tooltip.show = false;
                    option.tooltip.formatter = function () {
                        return '';
                    }
                } else {
                    option.tooltip.show = true;
                    option.tooltip.formatter = function (params) {
                        let title = option.radar.indicator[num].text;
                        let scond = params.data.value[num];
                        return `<div>
                            <p class="tooltip-title">${title}</p>
                            <div class="content-panel">
                                <span style="color:blue">●</span>
                                <span>分数:</span>
                                <span class="tooltip-value">${scond}</span>
                            </div>
                        </div>`;
                    }
                    //resultData
                    this.currentSelect.title = option.radar.indicator[num].text;
                    this.currentSelect.desc = option.radar.indicator[num].desc;

                }
                myChart.setOption(option);
            })
        },
        async getGraphData() {
            this.loading = true
            const res = await this.$http.postJson("/api/sendSupplyGraph", {
                "component": this.resultData.component || "github.com/rai-project/dlframework",
                "version": this.resultData.version || "v0.2.23-0.20180803211046-0bf83e30cbf8",
                "ecology": this.resultData.ecology || "Go"
            })
            // 处理数据
            await this.initData(res)

            this.loading = false
        },
        initData(res) {
            console.log("节点原始数据", res)
            let nodes = []
            let edges = []

            nodes = res.nodes.map(item => {
                let nodeItem = item.properties
                let fillColor = '#5B8FF9' //其他的组件（label:component）：蓝色；
                if (nodeItem.label == 'component' && nodeItem.name == this.search.component) {
                    fillColor = 'red'
                } else if (nodeItem.label == 'cve') {
                    fillColor = 'yellow'
                } else if (nodeItem.label == 'license') {
                    fillColor = 'green'
                }
                return {
                    id: nodeItem.id,
                    label: `${nodeItem.label || ''}\n${nodeItem.name}`,
                    children: item.children,
                    info: nodeItem,
                    style: {
                        fill: fillColor, //节点填充色
                    },
                }
            })
            edges = res.edges.map(item => {
                return {
                    source: item.source,
                    target: item.target,
                    label: item.label,
                    info: item
                }
            })
            this.graphData = {
                nodes,
                edges
            }

        },
        // 下钻子节点
        async getChildren({ spaceName = 'AI_supply', id, label, label1, isAll }) {
            this.loading = true
            let res
            if (isAll) {
                res = await this.$http.fetchGet('/api/deepAllChild', {
                    spaceName,
                    id,
                    label
                })
            } else {
                res = await this.$http.fetchGet('/api/deepOneTypeChild', {
                    spaceName,
                    id,
                    label,
                    label1: label1
                })
            }


            res.nodes = res.nodes.map(item => {
                let nodeItem = item.properties
                let fillColor = '#5B8FF9' //其他的组件（label:component）：蓝色；
                if (nodeItem.label == 'component' && nodeItem.name == this.search.component) {
                    fillColor = 'red'
                } else if (nodeItem.label == 'cve') {
                    fillColor = 'yellow'
                } else if (nodeItem.label == 'license') {
                    fillColor = 'green'
                }
                return {
                    ...nodeItem,
                    children: item.children,
                    info: nodeItem,
                    label: `${nodeItem.label || ''}\n${nodeItem.name}`,
                    style: {
                        fill: fillColor, //节点填充色
                    },
                }
            })
            res.edges = res.edges.map(item => {
                return {
                    source: item.source,
                    target: item.target,
                    label: item.properties.label,
                    info: item.properties
                }
            })
            console.log("res", res)
            this.mergeData(res)

            this.$nextTick(() => {
                this.loading = false
                console.log("this.loading", this.loading)
            })
        },
        // 合并数据
        mergeData({ edges, nodes }) {
            console.log("edges, nodes", edges, nodes)
            let graphData = this.graphData
            this.graphData = { nodes: [...graphData.nodes, ...nodes], edges: [...graphData.edges, ...edges] }
        },
        // 获取历史图谱
        async getGraphList() {
            const res = await this.$http.fetchGet('/api/findAllGraph', {
                spaceName: "AI_supply"
            })
            this.tableData = res
        },
        // 查看图谱
        handleLook(row) {
            this.graphData = row.graphInfo
        },
        // 删除图谱
        async handleDelete(row) {
            const res = await this.$http.fetchGet('/api/deleteGraph', {
                id: row.id
            })
            this.$message.success("删除成功")
            this.getGraphList()
        },
    }
};
</script>

<style scoped>
.common-width {
    width: 200px;
}

.common-select {
    width: 350px;
}

.common-input {
    width: 350px;
}

.small-input {
    width: 225px;
}

.table {
    width: 100%;
    font-size: 14px;
}

.label {
    font-size: 14px;
    font-weight: bold;
    color: black;
}

.text {
    font-size: 14px;
    margin-top: 8px;
    color: black;
}

.echart {
    width: 500px;
    height: 350px;
    margin-left: 25vh;
}

.g6-menu {
    list-style: none;
    margin: 0;
    padding: 0;
}

.g6-menu li {
    padding: 10px 20px;
    cursor: pointer;
    transition: background-color 0.3s;
}

.g6-menu li:hover {
    background-color: #f5f7fa;
}

.main-content {
    display: flex;
    height: 70vh;
    box-sizing: border-box;
    overflow: hidden;

    .left {
        height: 100%;
        width: 25%;
    }

    .right {
        width: 75%;
        height: 100%;
        margin-left: 20px;
    }
}
</style>